Vue Router vuex原理分析|原理篇
30 秒速记
- 核心判断:前端路由的本质是监听地址变化、匹配路由表,再驱动视图切换而不请求整页文档
- 原理主线:围绕 「vue-router」、「Vuex」、「核心机制」 建立输入、状态变化与输出之间的因果关系
- 文章范围:分析了Vue Router和Vuex的原理,包括路由管理、状态管理的实现机制、源码解析及其在Vue项目中的集成方法,帮助开发者深入理解Vue核心插件的工作原理和使用方式。
- 边界与代价:
hash与history的事件和服务端回退要求不同,鉴权、懒加载与滚动恢复属于路由之上的工程能力 - 工程落地:选型时同时验证首屏直达、前进后退、刷新回源、动态参数和未匹配路由
vue-router 负责让地址变化驱动组件切换,Vuex 则用响应式状态和固定入口管理跨组件数据。 路由插件监听 hashchange 或 popstate,把当前地址设为响应式数据,再由 router-view 根据路由表渲染匹配组件。状态管理中,commit 执行 mutation 修改 state,dispatch 调用 action 承载异步逻辑,getter 负责派生状态。前者解决单页导航,后者解决共享状态;如果组件状态不需要共享,就没必要都放进集中式存储。
这篇文章不要按 API 清单来背。先用上面的 Mind Map 建立全局结构,再通过交互 DEMO 观察正常路径和边界路径如何改变状态;阅读正文时重点核对每一步的输入、负责执行的参与者、产生的中间状态以及最终可观察结果。遇到版本敏感结论,要把“历史实现”“当前行为”和“工程兼容策略”分开说明;遇到性能或架构取舍,则用实际指标、失败现象和验证手段支撑判断。
版本校准: 本文出现 Object.defineProperty、Dep、Watcher 和双端 Diff 时,主要描述 Vue 2 实现;Vue 3 使用 Proxy、effect 与新的渲染器路径。Vue 2 已于 2023-12-31 结束维护,新项目应以 Vue 3 为基线,旧项目参考 Vue 2 EOL 官方说明 制定迁移与安全策略。
# vue-router
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单⻚面应用变得易如反 掌。
安装: vue add router 核心步骤:
- 步骤一:使用vue-router插件,router.js
import Router from 'vue-router'
Vue.use(Router)
- 步骤二:创建Router实例,router.js
export default new Router({...})
- 步骤三:在根组件上添加该实例,main.js
import router from './router'
new Vue({
router,
}).$mount("#app");
- 步骤四:添加路由视图,
App.vue
<router-view></router-view>
导航
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
# vue-router源码实现
- 作为一个插件存在:实现
VueRouter类和install方法 - 实现两个全局组件:
router-view用于显示匹配组件内容,router-link用于跳转 - 监控
url变化:监听hashchange或popstate事件 - 响应最新
url:创建一个响应式的属性current,当它改变时获取对应组件并显示
创建kvue-router.js
// 我们的插件:
// 1.实现一个Router类并挂载期实例
// 2.实现两个全局组件router-link和router-view
let Vue;
class VueRouter {
// 核心任务:
// 1.监听url变化
constructor(options) {
this.$options = options;
// 缓存path和route映射关系
// 这样找组件更快
this.routeMap = {}
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route
})
// 数据响应式
// 定义一个响应式的current,则如果他变了,那么使用它的组件会rerender
Vue.util.defineReactive(this, 'current', '')
// 请确保onHashChange中this指向当前实例
window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
}
onHashChange() {
// console.log(window.location.hash);
this.current = window.location.hash.slice(1) || '/'
}
}
// 插件需要实现install方法
// 接收一个参数,Vue构造函数,主要用于数据响应式
VueRouter.install = function (_Vue) {
// 保存Vue构造函数在VueRouter中使用
Vue = _Vue
// 任务1:使用混入来做router挂载这件事情
Vue.mixin({
beforeCreate() {
// 只有根实例才有router选项
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
// 任务2:实现两个全局组件
// router-link: 生成一个a标签,在url后面添加#
// <a href="#/about">aaaa</a>
// <router-link to="/about">aaa</router-link>
Vue.component('router-link', {
props: {
to: {
type: String,
required: true
},
},
render(h) {
// h(tag, props, children)
return h('a',
{ attrs: { href: '#' + this.to } },
this.$slots.default
)
// 使用jsx
// return <a href={'#'+this.to}>{this.$slots.default}</a>
}
})
Vue.component('router-view', {
render(h) {
// 根据current获取组件并render
// current怎么获取?
// console.log('render',this.$router.current);
// 获取要渲染的组件
let component = null
const { routeMap, current } = this.$router
if (routeMap[current]) {
component = routeMap[current].component
}
return h(component)
}
})
}
export default VueRouter
# Vuex
Vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化
# 整合vuex
vue add vuex
核心概念
- state 状态、数据
- mutations 更改状态的函数
- actions 异步操作
- store 包含以上概念的容器
- 状态 - state
state保存应用状态
export default new Vuex.Store({ state: { counter:0 },})
- 状态变更 - mutations
mutations用于修改状态,store.js
export default new Vuex.Store({
mutations:
{
add(state) {
state.counter++
}
}
})
- 派生状态 - getters
从state派生出新状态,类似计算属性
export default new Vuex.Store({
getters:
{
doubleCounter(state) { // 计算剩余数量 return state.counter * 2;
}
}
})
- 动作 - actions
加业务逻辑,类似于controller
export default new Vuex.Store({
actions:
{
add({
commit
}) {
setTimeout(() = >{}
}
})
测试代码:
<p @click="$store.commit('add')">counter: {{$store.state.counter}}</p>
<p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p>
<p>double:{{$store.getters.doubleCounter}}</p>
# vuex原理解析
- 实现一个插件:声明Store类,挂载$store
- Store具体实现:
- 创建响应式的state,保存mutations、actions和getters
- 实现commit根据用户传入type执行对应mutation
- 实现dispatch根据用户传入type执行对应action,同时传递上下文
- 实现getters,按照getters定义对state做派生
